﻿package com.janisRadins.asDraw.svg {
	import flash.geom.Point;
	/**
	 * SVG path segment data holder
	 * @author Jānis Radiņš
	 */
	public class PathSegment {
		public static const PATHSEG_UNKNOWN:uint = 0;
		public static const PATHSEG_CLOSEPATH:uint = 1;
		public static const PATHSEG_MOVETO_ABS:uint = 2;
		public static const PATHSEG_MOVETO_REL:uint = 3;
		public static const PATHSEG_LINETO_ABS:uint = 4;
		public static const PATHSEG_LINETO_REL:uint = 5;
		public static const PATHSEG_CURVETO_CUBIC_ABS:uint = 6;
		public static const PATHSEG_CURVETO_CUBIC_REL:uint = 7;
		public static const PATHSEG_CURVETO_QUADRATIC_ABS:uint = 8;
		public static const PATHSEG_CURVETO_QUADRATIC_REL:uint = 9;
		public static const PATHSEG_ARC_ABS:uint = 10;
		public static const PATHSEG_ARC_REL:uint = 11;
		public static const PATHSEG_LINETO_HORIZONTAL_ABS:uint = 12;
		public static const PATHSEG_LINETO_HORIZONTAL_REL:uint = 13;
		public static const PATHSEG_LINETO_VERTICAL_ABS:uint = 14;
		public static const PATHSEG_LINETO_VERTICAL_REL:uint = 15;
		public static const PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:uint = 16;
		public static const PATHSEG_CURVETO_CUBIC_SMOOTH_REL:uint = 17;
		public static const PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:uint = 18;
		public static const PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:uint = 19;
		/**
		 * Converts path segment literal type to numeric alternative
		 * @param	literal String with path segment literal representation
		 * @return	Coresponding numeric value for input path segment type 
		 */
		public static function literalTypeToPathType(literal:String):uint {
			switch(literal) {
				case 'Z' : 
				case 'z' : return PATHSEG_CLOSEPATH;
				case 'M' : return PATHSEG_MOVETO_ABS;
				case 'm' : return PATHSEG_MOVETO_REL;
				case 'L' : return PATHSEG_LINETO_ABS;
				case 'l' : return PATHSEG_LINETO_REL;
				case 'C' : return PATHSEG_CURVETO_CUBIC_ABS;
				case 'c' : return PATHSEG_CURVETO_CUBIC_REL;
				case 'Q' : return PATHSEG_CURVETO_QUADRATIC_ABS;
				case 'q' : return PATHSEG_CURVETO_QUADRATIC_REL;
				case 'A' : return PATHSEG_ARC_ABS;
				case 'a' : return PATHSEG_ARC_REL;
				case 'H' : return PATHSEG_LINETO_HORIZONTAL_ABS;
				case 'h' : return PATHSEG_LINETO_HORIZONTAL_REL;
				case 'V' : return PATHSEG_LINETO_VERTICAL_ABS;
				case 'v' : return PATHSEG_LINETO_VERTICAL_REL;
				case 'S' : return PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
				case 's' : return PATHSEG_CURVETO_CUBIC_SMOOTH_REL;
				case 'T' : return PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
				case 't' : return PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL;
			}
			return PATHSEG_UNKNOWN;
		}
		/**
		 * Converts path segment numeric type to literal alternative
		 * @param	type Path type numeric representation
		 * @return	Coresponding literal value for input path segment type 
		 */
		public static function pathTypeToLiteralType(type:uint):String {
			switch(type) {
				case PATHSEG_CLOSEPATH						: return 'z';
				case PATHSEG_MOVETO_ABS						: return 'M';
				case PATHSEG_MOVETO_REL						: return 'm';
				case PATHSEG_LINETO_ABS						: return 'L';
				case PATHSEG_LINETO_REL						: return 'l';
				case PATHSEG_CURVETO_CUBIC_ABS				: return 'C';
				case PATHSEG_CURVETO_CUBIC_REL				: return 'c';
				case PATHSEG_CURVETO_QUADRATIC_ABS			: return 'Q';
				case PATHSEG_CURVETO_QUADRATIC_REL			: return 'q';
				case PATHSEG_ARC_ABS						: return 'A';
				case PATHSEG_ARC_REL						: return 'a';
				case PATHSEG_LINETO_HORIZONTAL_ABS			: return 'H';
				case PATHSEG_LINETO_HORIZONTAL_REL			: return 'h';
				case PATHSEG_LINETO_VERTICAL_ABS			: return 'V';
				case PATHSEG_LINETO_VERTICAL_REL			: return 'v';
				case PATHSEG_CURVETO_CUBIC_SMOOTH_ABS		: return 'S';
				case PATHSEG_CURVETO_CUBIC_SMOOTH_REL		: return 's';
				case PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS	: return 'T';
				case PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL	: return 't';
			}
			return null;
		}
		/** @private **/
		protected var _pathSegType:uint = PATHSEG_UNKNOWN;
		/** @private **/
		protected var _pathSegTypeAsLetter:String = null;
		/** @private **/
		protected var _data:Array;
		/**
		 * Constructor
		 * Atleast one of type | typeAsLetter must be set in order to define path segment type
		 * @param	type			Path segment type numeric representation
		 * @param	typeAsLetter	Path segment type string  representation
		 * @param	data			Path segment data
		 */
		public function PathSegment(data:Array, typeAsLetter:String = null, type:int = -1) {
			if (type == -1 && typeAsLetter != null) {
				_pathSegTypeAsLetter = typeAsLetter;
				_pathSegType = literalTypeToPathType(_pathSegTypeAsLetter);
			} else if (type > 0) {
				_pathSegType = type;
				_pathSegTypeAsLetter = pathTypeToLiteralType(_pathSegType);
			}
			_data = data;
		}
		/**
		 * Numeric segment type id
		 */
		public function get pathSegType():uint { 
			return _pathSegType;
		}
		/**
		 * String segment type
		 */
		public function get pathSegTypeAsLetter():String {
			return _pathSegTypeAsLetter;
		}
		/**
		 * Data of path segment
		 */
		public function get data():Array {
			return _data;
		}
		/**
		 * Flag which indicates that PathSegment is using absolute coorginates
		 */
		public function get absCoords():Boolean {
			return _pathSegTypeAsLetter == _pathSegTypeAsLetter.toUpperCase();
		}
		/**
		 * Method which returns shifted copy of path segment data
		 * @param	p	Point value by which data should be shifted
		 * @return	altered copy of data array
		 */
		public function getShiftedData(p:Point):Array {
			var d:Array = _data.concat();
			for (var i:uint = 0; i, d.length; i++) {
				d[i] += (i % 2 == 0 ? p.x : p.y);
			}
			return d;
		}
		/**
		 * @return Class string representation
		 */
		public function toString():String {
			return "PathSegment [pathSegType:" + pathSegType + ", pathSegTypeAsLetter:" + _pathSegTypeAsLetter + " data:" + _data + "]";
		}
	}
}